package com.ysy.tz.core.validator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;

public class Check {
    private Map<String, ObservableValue<? extends Object>> dependencies = new HashMap(1);
    private Consumer<Context> checkMethod;
    private ReadOnlyObjectWrapper<ValidationResult> validationResultProperty = new ReadOnlyObjectWrapper();
    private ValidationResult nextValidationResult = new ValidationResult();
    private List<Node> targets = new ArrayList(1);
    private List<Decoration> decorations = new ArrayList();
    private Function<ValidationMessage, Decoration> decorationFactory;
    private ChangeListener<? super Object> dependencyListener;

    public Check() {
        this.validationResultProperty.set(new ValidationResult());
        this.decorationFactory = DefaultDecoration.getFactory();
        this.dependencyListener = (obs, oldv, newv) -> {
            this.recheck();
        };
    }

    public Check withMethod(Consumer<Context> checkMethod) {
        this.checkMethod = checkMethod;
        return this;
    }

    public Check dependsOn(String key, ObservableValue<? extends Object> dependency) {
        this.dependencies.put(key, dependency);
        return this;
    }

    public Check decorates(Node target) {
        this.targets.add(target);
        return this;
    }

    public Check decoratingWith(Function<ValidationMessage, Decoration> decorationFactory) {
        this.decorationFactory = decorationFactory;
        return this;
    }

    public Check immediate() {
        Iterator var1 = this.dependencies.values().iterator();

        while(var1.hasNext()) {
            ObservableValue<? extends Object> dependency = (ObservableValue)var1.next();
            dependency.addListener(this.dependencyListener);
        }

        Platform.runLater(this::recheck);
        return this;
    }

    public Check immediateNoRecheck() {
        Iterator var1 = this.dependencies.values().iterator();

        while(var1.hasNext()) {
            ObservableValue<? extends Object> dependency = (ObservableValue)var1.next();
            dependency.addListener(this.dependencyListener);
        }

        return this;
    }

    public void recheck() {
        this.nextValidationResult = new ValidationResult();
        this.checkMethod.accept(new Context());
        Iterator var1 = this.targets.iterator();

        Node target;
        Iterator var3;
        while(var1.hasNext()) {
            target = (Node)var1.next();
            var3 = this.decorations.iterator();

            while(var3.hasNext()) {
                Decoration decoration = (Decoration)var3.next();
                decoration.remove(target);
            }
        }

        this.decorations.clear();
        var1 = this.targets.iterator();

        while(var1.hasNext()) {
            target = (Node)var1.next();
            var3 = this.nextValidationResult.getMessages().iterator();

            while(var3.hasNext()) {
                ValidationMessage validationMessage = (ValidationMessage)var3.next();
                Decoration decoration = (Decoration)this.decorationFactory.apply(validationMessage);
                this.decorations.add(decoration);
                decoration.add(target);
            }
        }

        if (!this.nextValidationResult.getMessages().equals(this.getValidationResult().getMessages())) {
            this.validationResultProperty.set(this.nextValidationResult);
        }

    }

    public ValidationResult getValidationResult() {
        return (ValidationResult)this.validationResultProperty.get();
    }

    public ReadOnlyObjectProperty<ValidationResult> validationResultProperty() {
        return this.validationResultProperty.getReadOnlyProperty();
    }

    public class Context {
        private Context() {
        }

        public <T> T get(String key) {
            return (T)((ObservableValue)Check.this.dependencies.get(key)).getValue();
        }

        public Iterable<String> keys() {
            return Check.this.dependencies.keySet();
        }

        public void warn(String message) {
            Check.this.nextValidationResult.addWarning(message);
        }

        public void error(String message) {
            Check.this.nextValidationResult.addError(message);
        }
    }
}
